package com.xzzz.irda.guardcat.client.heartbeat;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.xzzz.common.base.enums.FrameworkEnum;
import com.xzzz.common.base.util.SystemUtil;
import com.xzzz.common.base.util.okhttp.HttpUtil;
import com.xzzz.common.base.util.json.JsonUtil;
import com.xzzz.common.base.util.spring.SpringUtil;
import com.xzzz.common.base.util.thread.NamedThreadFactory;
import com.xzzz.irda.guardcat.client.GuardcatClientProperties;
import com.xzzz.irda.guardcat.core.constants.GuardcatConstant;
import com.xzzz.irda.guardcat.core.pojo.Heartbeat;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.web.context.WebServerInitializedEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.context.EnvironmentAware;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;

import java.lang.management.ManagementFactory;
import java.lang.management.RuntimeMXBean;
import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * @author xzzz
 */
@Slf4j
@Component
public class HeartbeatClientServiceImpl implements EnvironmentAware, ApplicationListener<WebServerInitializedEvent> {

    /**
     * 心跳对象
     */
    private static final Heartbeat HEARTBEAT_REQUEST = new Heartbeat();

    @Autowired
    private GuardcatClientProperties guardcatClientProperties;

    private Integer sendHeartbeatErrorNum = 0;
    private static final String START_TIME = DateUtil.now();
    private static final Long START_TIMESTAMP = System.currentTimeMillis();

    /**
     * 心跳线程池
     */
    private final ScheduledExecutorService heartbeatSchedule = new ScheduledThreadPoolExecutor(1,
            new NamedThreadFactory("guardcat-client-heartbeat-send-task"));

    static {
        HEARTBEAT_REQUEST.setHostName(SystemUtil.getHostName());
        HEARTBEAT_REQUEST.setIp(SystemUtil.getIp());
        HEARTBEAT_REQUEST.setMachineId(GuardcatConstant.MACHINE_ID);
        HEARTBEAT_REQUEST.setFrameworks(FrameworkEnum.getExistFramework());

        try {
            HEARTBEAT_REQUEST.setStartTime(START_TIME);
            HEARTBEAT_REQUEST.setProcessId(getProcessId());
            HEARTBEAT_REQUEST.setProcessName(getProcessName());
        } catch (Exception e) {
            HEARTBEAT_REQUEST.setStartTime(DateUtil.now());
            HEARTBEAT_REQUEST.setProcessId(-1);
            HEARTBEAT_REQUEST.setProcessName("获取JVM信息错误,未获取到进程名称");
        }
    }

    /**
     * JVM进程ID
     */
    public static int getProcessId() {
        RuntimeMXBean runtimeMxBean = ManagementFactory.getRuntimeMXBean();
        return Integer.parseInt(runtimeMxBean.getName().split("@")[0]);
    }

    /**
     * 获取JVM名称
     */
    public static String getProcessName() {
        RuntimeMXBean runtimeMxBean = ManagementFactory.getRuntimeMXBean();
        return runtimeMxBean.getName();
    }

    /**
     * 容器初始化完成
     */
    public void init() {
        if (StrUtil.isBlank(guardcatClientProperties.getServerUrl())) {
            log.info("[GUARDCAT] 未配置监控服务端地址");
            return;
        }
        // 客户端JAR包版本
        HEARTBEAT_REQUEST.setAppVersion(guardcatClientProperties.getAppVersion());
        // 拉取全部APP指标信息
        heartbeatSchedule.scheduleAtFixedRate(() -> {
            try {
                HEARTBEAT_REQUEST.setTimestamp(System.currentTimeMillis());
                HEARTBEAT_REQUEST.setUptime(HEARTBEAT_REQUEST.getTimestamp() - START_TIMESTAMP);
                String body = JsonUtil.toJson(HEARTBEAT_REQUEST);
                HttpUtil.post(guardcatClientProperties.getServerUrl() + GuardcatConstant.API.HEARTBEAT, body);
                sendHeartbeatErrorNum = 0;
            } catch (Exception e) {
                log.warn("[GUARDCAT] BEAT 心跳发送失败-{}: {}", sendHeartbeatErrorNum, e.getMessage());
                sendHeartbeatErrorNum++;
            }
        }, 5000, guardcatClientProperties.getHeartbeatIntervalMs(), TimeUnit.MILLISECONDS);
    }

    @Override
    public void setEnvironment(Environment environment) {
        String profilesActive = environment.getProperty(SpringUtil.PROFILE_ACTION);
        if (StrUtil.isBlank(profilesActive)) {
            profilesActive = "none";
        }

        String appName = environment.getProperty(SpringUtil.APP_NAME);

        if (StrUtil.isBlank(appName)) {
            appName = environment.getProperty(SpringUtil.SERVLET_CONTEXT_PATH);
        }

        if (StrUtil.isBlank(appName)) {
            appName = "未知服务名称";
        }

        HEARTBEAT_REQUEST.setAppName(appName);
        HEARTBEAT_REQUEST.setProfilesActive(profilesActive);
        HEARTBEAT_REQUEST.setPort(Integer.valueOf(Objects.requireNonNull(environment.getProperty(SpringUtil.SERVER_PORT))));

        String contentPath = Optional.ofNullable(environment.getProperty(SpringUtil.SERVLET_CONTEXT_PATH)).orElse("");
        HEARTBEAT_REQUEST.setServletContextPath(contentPath);
    }

    @Override
    public void onApplicationEvent(WebServerInitializedEvent event) {
        this.init();
    }

}
